package com.iplant.mes.serviceImpl;

import com.iplant.ams.service.basicenum.dms.scada.DMSDataClass;
import com.iplant.ams.service.po.dms.DMSDeviceLedger;
import com.iplant.ams.service.po.dms.scada.conf.DMSDeviceParameter;
import com.iplant.ams.service.po.dms.scada.record.DMSProcessRecord;
import com.iplant.ams.serviceImpl.dao.dms.scada.DMSProcessRecordDAO;
import com.iplant.aps.service.po.aps.APSTaskPartPoint;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.base.utils.sql.orm.PoService;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.mes.service.MESService;
import com.iplant.mes.service.mesenum.sfc.SFCTaskStatus;
import com.iplant.mes.service.po.sfc.*;
import com.iplant.mes.service.po.sfc.autoStation.SFCDeviceSelfData;
import com.iplant.mes.service.po.sfc.autoStation.SFCDeviceSelfDataItem;
import com.iplant.mes.serviceImpl.dao.sfc.SFCTaskSelfDAO;
import com.iplant.pdm.service.po.fpc.FPCProductCom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MESServiceImpl implements MESService {

    //region 构造函数
    public MESServiceImpl() {
    }
    //endregion

    //region 单实例

    private static MESService Instance = null;

    public static MESService getInstance() {
        if (Instance == null)
            Instance = new MESServiceImpl();

        return Instance;
    }

    //endregion

    //region POService
    PoService<SFCTaskSelf> mSFCTaskSelfService = ORMUtils.GetPoService(SFCTaskSelf.class);
    PoService<APSTaskPartPoint> mAPSTaskPartPointeService = ORMUtils.GetPoService(APSTaskPartPoint.class);
    PoService<FPCProductCom> mFPCProductComService = ORMUtils.GetPoService(FPCProductCom.class);
    PoService<DMSDeviceParameter> mDMSDeviceParameterService = ORMUtils.GetPoService(DMSDeviceParameter.class);
    //endregion

    //region 作业

    @Override
    public ServiceResult<Integer> SFC_AutoCloseTaskSelfList(BMSEmployee wLoginUser) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            Calendar wBaseTime = Calendar.getInstance();
            wBaseTime.set(2010, 0, 1, 0, 0, 0);

            Calendar wSTime = Calendar.getInstance();
            wSTime.set(wSTime.get(Calendar.YEAR), wSTime.get(Calendar.MONTH), wSTime.get(Calendar.DATE), 0, 0, 0);
            wSTime.add(Calendar.SECOND, -1);

            OutResult<Integer> wErrorCode = new OutResult<Integer>(0);
            //①获取当日之前的派工任务
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("StaStartTime", wBaseTime);
            wParams.put("StaEndTime", wSTime);
            wParams.put("Status", "1,2,3,5");
            wParams.put("Active", 1);
            wParams.put("IsRepairPlan", 0);
            List<SFCTaskSelf> wSFCTaskSelfList = mSFCTaskSelfService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            //②关闭派工任务
            for (SFCTaskSelf wSFCTaskSelf : wSFCTaskSelfList) {
                wSFCTaskSelf.setUserInfo(wLoginUser);
                wSFCTaskSelf.Status = SFCTaskStatus.Done.getValue();
                wSFCTaskSelf.Description = "系统自动完工";
                mSFCTaskSelfService.UpdatePo(wLoginUser, wSFCTaskSelf, wErrorCode);
            }
        } catch (Exception ex) {
            log.error("SFC_AutoCloseTaskSelfList", ex);
            wResult.FaultCode += ex.getMessage();
        }
        return wResult;
    }


    /**
     * 将设备采集数据结构转为自检
     *
     * @param wLoginUser
     * @param wProcessRecordList
     * @return
     */
    @Override
    public ServiceResult<Integer> MES_ProcessToSelf(BMSEmployee wLoginUser, DMSDeviceLedger dmsDeviceLedger,
                                                    List<DMSProcessRecord> wProcessRecordList
            , List<DMSDeviceParameter> wDMSDeviceParameterList) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {

            List<SFCDeviceSelfData> wSFCDeviceSelfDataList;
            ServiceResult<Integer> wServiceResult;
            OutResult<Integer> wErrorCode = new OutResult<Integer>(0);
            int wUploadStatus;
            for (DMSProcessRecord dmsProcessRecord : wProcessRecordList) {
                //todo 彭尤旺 转换自检
                wSFCDeviceSelfDataList = GetSFCDeviceSelfDataList(wLoginUser, dmsProcessRecord,
                        wDMSDeviceParameterList);
                wServiceResult =
                        SFCServiceImpl.getInstance().SFC_DeviceBatchSelfCheck(wLoginUser,
                                wSFCDeviceSelfDataList);
                // 转换完成后将DMSProcessRecord 中的UploadStatus改为1 （失败的不改 或者改为2）
                if (StringUtils.isEmpty(wServiceResult.FaultCode) || wServiceResult.FaultCode.contains("首检未完成")) {
                    dmsProcessRecord.UpdateStatus = 1;
                } else {
                    dmsProcessRecord.UpdateStatus = 2;
                }
                // 更新备注
                dmsProcessRecord.Remark = wServiceResult.FaultCode;
                DMSProcessRecordDAO.getInstance().DMS_UpdateProcessRecordRemark(wLoginUser, dmsDeviceLedger,
                        dmsProcessRecord);
            }
        } catch (Exception ex) {
            log.error("MES_ProcessToSelf", ex);
            wResult.FaultCode += ex.getMessage();
        }
        return wResult;
    }

    /**
     * 转换结构，批量自检
     */
    private List<SFCDeviceSelfData> GetSFCDeviceSelfDataList(BMSEmployee wLoginUser,
                                                             DMSProcessRecord wDMSProcessRecord,
                                                             List<DMSDeviceParameter> wDMSDeviceParameterList) {
        List<SFCDeviceSelfData> wResult = new ArrayList<SFCDeviceSelfData>();
        try {
            SFCDeviceSelfData wSFCDeviceSelfData = new SFCDeviceSelfData();
            wSFCDeviceSelfData.TaskSelfID = wDMSProcessRecord.SFCOrderID;
            wSFCDeviceSelfData.WorkpieceNo = wDMSProcessRecord.WorkpieceNo;
            wSFCDeviceSelfData.OrderID = wDMSProcessRecord.OrderID;
            wSFCDeviceSelfData.CheckResult = wDMSProcessRecord.Status;
            wSFCDeviceSelfData.ParamValueList = new ArrayList<>();
            SimpleDateFormat wSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SFCDeviceSelfDataItem wSFCDeviceSelfDataItem;

            //提取作业参数
            DMSDeviceParameter dmsDeviceParameter;
            for (String wParamName : wDMSProcessRecord.ProductParams.keySet()) {
                Optional<DMSDeviceParameter> wDMSDeviceParameterOption =
                        wDMSDeviceParameterList.stream().filter(p -> p.DataClass == DMSDataClass.WorkParams.getValue() && p.VariableName.equals(wParamName)).findFirst();
                if (!wDMSDeviceParameterOption.isPresent()) {
                    continue;
                }
                dmsDeviceParameter =
                        wDMSDeviceParameterOption.get();
                wSFCDeviceSelfDataItem = new SFCDeviceSelfDataItem();
                wSFCDeviceSelfDataItem.AssetNo = dmsDeviceParameter.AssetNo;
                wSFCDeviceSelfDataItem.ParameterNo = dmsDeviceParameter.Code;
                wSFCDeviceSelfDataItem.ParameterValue =
                        StringUtils.parseString(wDMSProcessRecord.ProductParams.get(wParamName));
                wSFCDeviceSelfData.ParamValueList.add(wSFCDeviceSelfDataItem);
            }
            //提取质量参数
            for (String wParamName : wDMSProcessRecord.CheckParams.keySet()) {
                Optional<DMSDeviceParameter> wDMSDeviceParameterOption =
                        wDMSDeviceParameterList.stream().filter(p -> p.DataClass == DMSDataClass.QualityParams.getValue() && p.VariableName.equals(wParamName)).findFirst();
                if (!wDMSDeviceParameterOption.isPresent()) {
                    continue;
                }
                dmsDeviceParameter =
                        wDMSDeviceParameterOption.get();
                wSFCDeviceSelfDataItem = new SFCDeviceSelfDataItem();
                wSFCDeviceSelfDataItem.AssetNo = dmsDeviceParameter.AssetNo;
                wSFCDeviceSelfDataItem.ParameterNo = dmsDeviceParameter.Code;
                wSFCDeviceSelfDataItem.ParameterValue =
                        StringUtils.parseString(wDMSProcessRecord.CheckParams.get(wParamName));
                wSFCDeviceSelfData.ParamValueList.add(wSFCDeviceSelfDataItem);
            }
            //提取工艺参数
            for (String wParamName : wDMSProcessRecord.TechnologyParams.keySet()) {
                Optional<DMSDeviceParameter> wDMSDeviceParameterOption =
                        wDMSDeviceParameterList.stream().filter(p -> p.DataClass == DMSDataClass.TechnologyData.getValue() && p.VariableName.equals(wParamName)).findFirst();
                if (!wDMSDeviceParameterOption.isPresent()) {
                    continue;
                }
                dmsDeviceParameter =
                        wDMSDeviceParameterOption.get();
                wSFCDeviceSelfDataItem = new SFCDeviceSelfDataItem();
                wSFCDeviceSelfDataItem.AssetNo = dmsDeviceParameter.AssetNo;
                wSFCDeviceSelfDataItem.ParameterNo = dmsDeviceParameter.Code;
                wSFCDeviceSelfDataItem.ParameterValue =
                        StringUtils.parseString(wDMSProcessRecord.TechnologyParams.get(wParamName));
                wSFCDeviceSelfData.ParamValueList.add(wSFCDeviceSelfDataItem);
            }

            wResult.add(wSFCDeviceSelfData);
        } catch (Exception e) {
            log.error("GetSFCDeviceSelfDataList", e);
        }
        return wResult;
    }

    @Override
    public ServiceResult<Integer> MES_AutoProcessToSelf(BMSEmployee wLoginUser) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            List<DMSDeviceLedger> wDeviceLedgerList = CacheUtils.GetCacheTList(DMSDeviceLedger.class);
            OutResult<Integer> wErrorCode = new OutResult<>(0);
            List<DMSProcessRecord> wProcessRecordList = new ArrayList<>();
            List<Integer> wRecordIDList;

            ServiceResult<Integer> wProcessResult;
            Map<String, Object> wParams = new HashMap<String, Object>();
            List<DMSDeviceParameter> wDMSDeviceParameterList;

            Pagination wPagination = Pagination.Create(1, 30, "ID ASC");

            for (DMSDeviceLedger dmsDeviceLedger : wDeviceLedgerList) {

                wProcessRecordList = DMSProcessRecordDAO.getInstance().DMS_UploadProcessRecordList(wLoginUser,
                        dmsDeviceLedger, wPagination, wErrorCode);

                if (wErrorCode.Result != 0) {
                    wResult.AddFaultCode(wErrorCode);
                    continue;
                }
                if (wProcessRecordList.size() == 0)
                    continue;

                wRecordIDList =
                        wProcessRecordList.stream().map(p -> p.ID).distinct().collect(Collectors.toList());

                DMSProcessRecordDAO.getInstance().DMS_UpdateProcessRecordUploadStatus(wLoginUser, wRecordIDList,
                        dmsDeviceLedger, 2,
                        wErrorCode);

                if (wErrorCode.Result != 0) {
                    wResult.AddFaultCode(wErrorCode);
                    continue;
                }

                wParams.put("DeviceID", dmsDeviceLedger.ID);
                wParams.put("DataClass", "4,6,8");
                wParams.put("Active", 1);
                wDMSDeviceParameterList = mDMSDeviceParameterService.SelectPOList(wLoginUser,
                        wParams, Pagination.getNewMaxSize(),
                        wErrorCode);

                wProcessResult = this.MES_ProcessToSelf(wLoginUser, dmsDeviceLedger, wProcessRecordList,
                        wDMSDeviceParameterList);

                if (wProcessResult == null)
                    continue;

                if (StringUtils.isNotEmpty(wProcessResult.FaultCode)) {
                    wResult.FaultCode += wProcessResult.FaultCode;
                    continue;
                }

                wRecordIDList =
                        wProcessRecordList.stream().filter(p -> p.UpdateStatus == 1).map(p -> p.ID).distinct().collect(Collectors.toList());

                if (wRecordIDList.size() > 0) {
                    DMSProcessRecordDAO.getInstance().DMS_UpdateProcessRecordUploadStatus(wLoginUser, wRecordIDList,
                            dmsDeviceLedger, 1,
                            wErrorCode);
                    if (wErrorCode.Result != 0) {
                        wResult.AddFaultCode(wErrorCode);
                    }
                }
            }
            if (StringUtils.isNotEmpty(wResult.FaultCode)) {
                log.info(StringUtils.Format("MES_AutoProcessToSelf inner Error: {0}", wResult.FaultCode));
            }

        } catch (Exception e) {
            log.error("MES_AutoProcessToSelf", e);
            wResult.FaultCode += e.getMessage();
        }
        return wResult;
    }

    @Override
    public ServiceResult<Integer> MES_AutoUpdateHisActNum(BMSEmployee wLoginUser) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            //①查询未完成的工序计划
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("Status", "4,6");
            wParams.put("Active", 1);
            List<APSTaskPartPoint> wAPSTaskPartPointList = mAPSTaskPartPointeService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            if (wAPSTaskPartPointList == null || wAPSTaskPartPointList.size() <= 0) {
                return wResult;
            }
            //②查询产品组成数据
            List<FPCProductCom> wFPCProductComList = mFPCProductComService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            Map<Integer, List<FPCProductCom>> wProductIDComMap = wFPCProductComList.stream()
                    .collect(Collectors.groupingBy(FPCProductCom::getProductID));
            //③维护历史完成数

            for (APSTaskPartPoint wAPSTaskPartPoint : wAPSTaskPartPointList) {
                SFCTaskSelfDAO.getInstance().SFC_UpdatesPlanRealTimeProgress_PartPointPlan_His(wLoginUser,
                        wAPSTaskPartPoint, wProductIDComMap, CalendarTool.getDate(), wErrorCode);
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("MES_AutoUpdateHisActNum", e);
        }
        return wResult;
    }

//endregion
}
